/**
 * @class   wosh::URI
 * @brief   
 *
 *
 * regex are similar to xsl, but simplyfied
 *
 *
 ****************************************************************************
 * @version $Id: URI.h 2863 2010-08-07 04:28:58Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_URI_H__
 #define __WOSH_Core_URI_H__

 #include <woshDefs.h>
 #include <core/Serialization.h>

 #include <core/Containers.h> //uri-resolver
 #include <core/Utilities.h> //temp for UriExpression

 #include <core/Tree.h>
 #include <string>
 #include <vector>


namespace wosh {

#define _URI_PATH_Separator		"/"
#define _URI_KERNEL_Separator	":"

#define _URI_WILDCHAR			"*"
#define _URI_WILDWILDCHAR		"**"


struct UriPredicate {
	std::string field;
	std::string value;
	char comparison;
	bool or_and;
};

class UriExpression {
	public:
		enum COMPARSON_METHOD {
			EQUAL = '=',
			CONTAINS = '~'
		};
	public:
		/**
		 * @brief  Empty constructor.
		 */
		UriExpression() { }
		/**
		 * @brief  Empty destructor.
		 */
		virtual ~UriExpression() { }

/** @name Getters
 * @{
 ******************************************************************************/
	public:
		inline int size() const			{ return this->predicates.size(); }
		inline bool empty() const		{ return this->predicates.empty(); }

		bool isValid() const {
			if ( this->predicates.empty() ) return true;
			return true;
		 }

		UriPredicate getPredicate( int index ) const;
		UriPredicate getPredicate( const std::string& field ) const;

		const std::vector<UriPredicate>& getPredicates() const	{ return this->predicates; }
		std::vector<UriPredicate>& getPredicates()			 	{ return this->predicates; }

//@}
/** @name Setters
 * @{
 ******************************************************************************/
	public:
		void setPredicate( const std::string& field, const std::string& value, char comparison );
		virtual void fromString( const std::string& input );
		void clear();
//@}
/** @name Operators Overloading
 * @{
 ******************************************************************************/
	public:
		UriExpression& operator=(const UriExpression& m);
		bool operator==(const UriExpression &other) const;
		bool operator!=(const UriExpression &other) const	{ return !(*this == other);  }
//@}
/** @name Serialization interface
 * @{
 ******************************************************************************/
	public:
		virtual std::string toString() const;
//@}
	protected:
		std::vector<UriPredicate> predicates;

 };




class URICollector;

class URI : public virtual ISerializable
 {
	WOSH_SERIALIZABLE(wosh::URI)
	WOSH_COMPAREX_RTTI(wosh::URI)

	public:
		/**
		 * @brief  Empty constructor.
		 */
		URI();
		/**
		 * @brief  Constructor, initialized by a string representation of the URI.
		 * @param uristr [in] the string to be parsed
		 * @see    URI::fromString()
		 */
		URI( const std::string& uristr );
		/**
		 * @brief  Constructor, initialized by parent URI and a name.
		 * @param parent [in] the parent of the URI (will set: kernel, path)
		 * @param name [in] the name of the URI to be parsed
		 * @see    URI::setParent()
		 * @see    URI::setName()
		 */
		URI( const URI& parent, const std::string& name );
		/**
		 * @brief  Copy constructor.
		 * @param m [in] the source object to be copied
		 */
		URI( const URI& m );
		/**
		 * @brief  Empty destructor.
		 */
		virtual ~URI();

	public:
		WRESULT registerGlobal();
		WRESULT unRegisterGlobal();

		bool exists() const;

	public:
		static URI LocalKernel();


	public:
		/**
		 * @brief  Compare of an Object URI and a regex URI.
		 *         Only Kernel field is compared.
		 *         Supported regex expression are: '*' => any kernel
		 * @param [in] item the object's URI to be validated
		 * @param [in] regexURI the regex expression
		 * @return true when object's URI is validated by regex expression, false else.
		 * @bug    Supported regex expression are: '*' => any kernel
		 */
		static bool pregMatchKernel( const URI& regexURI, const URI& item );

		static bool pregMatchStep( const std::string& regex, const std::string& item );

		static bool pregMatch( const URI& regexURI, const URI& item );

		static bool extractExpression( const std::string& input, std::string& name, UriExpression& expression );


/** @name Getters
 * @{
 ******************************************************************************/
	public:
		bool isEmpty() const;
		bool isValid() const;
		inline bool isGlobal() const							{ return this->global; }
 		inline bool isBroadcast() const							{ return ( isNameAny() && (isPathEmpty() || isPathAny() ) ); }

		inline const std::string& getKernelName() const			{ return this->kernel_name; }
		inline std::string& getKernelName()						{ return this->kernel_name; }
		inline bool isKernelEmpty() const						{ return (this->kernel_name == ""); }
		bool isKernelLocal() const;
		inline bool isKernelEmptyOrLocal() const				{ return (isKernelEmpty() || isKernelLocal()); }
		inline bool isKernelAny() const							{ return (this->kernel_name == _URI_WILDCHAR); }

		inline const std::vector<std::string>& getPath() const	{ return this->path; }
		inline std::vector<std::string>& getPath()				{ return this->path; }
		inline bool isPathEmpty() const							{ return this->path.empty(); }
		inline bool isPathAny() const							{ return (this->path.size() == 1 && this->path.front() == _URI_WILDWILDCHAR ); }

		inline const std::string& getName() const				{ return this->name; }
		inline std::string& getName() 							{ return this->name; }
		inline bool isNameEmpty() const							{ return this->name.empty(); }
		inline bool isNameAny() const							{ return (this->name == _URI_WILDCHAR); }

		inline const UriExpression& getExpression() const	{ return this->expr; }
		inline UriExpression& getExpression() 			{ return this->expr; }
		inline bool hasExpression() const						{ return !this->expr.empty(); }

		inline bool hasParent() const							{ return (this->path.size() > 0); }
		URI getParent() const;
		bool isChildOf( const URI& parent, bool strict ) const;

//@}
/** @name Setters
 * @{
 ******************************************************************************/
	public:
		inline void setKernelName( const std::string& value )	{ this->kernel_name = value; }
		inline void setKernelAny()								{ this->kernel_name = _URI_WILDCHAR; }
		void setKernelLocal();

		inline void setPath( const std::vector<std::string>& value ) { this->path = value; }
		void setPath( const std::string& value );

		inline void setName( const std::string& value )			{ this->name = value; }
		inline void setNameAny()								{ this->name = _URI_WILDCHAR; }

		inline void setExpression( const UriExpression& exp ) { this->expr = exp; }

		void setAnyButName( const std::string& value );
		void setAny();
  		void setParent( const URI& value );

 		void clear();
		inline void clearPath()									{ this->path.clear(); }
 		void clearPathName();

		void fromString( const std::string& value );

		WRESULT replaceField( const std::string& key, const ISerializable* value );

//@}
/** @name Operators Overloading
 * @{
 ******************************************************************************/
	public:
		URI& operator=(const URI& m);
		bool operator==(const URI &other) const;
		bool operator!=(const URI &other) const			{ return !(*this == other);  }
		bool operator>(const URI& other) const;
		bool operator<(const URI& other) const;
//@}
/** @name Serialization interface
 * @{
 ******************************************************************************/
	public:
		virtual std::string toString() const;
		virtual bool updateHash( DataHashContext* hash_context ) const;
//@}
	private:
		std::string kernel_name;		///< name of the kernel
		std::string name;				///< name
		std::vector<std::string> path;	///< parent-child path
		UriExpression expr;				///< optional expression(s)

	private:
		bool global;
		friend class wosh::URICollector;


}; // class def


typedef TreeNodeT<std::string> NodeUriStr;


class URICollector
 {
	public:
		static inline TreeT<NodeUriStr>& getTree()		{ return getInstance().URIs; }
		static URI resolve( NodeUriStr* node );

	public:
		void registerGlobal( const URI* uri );
		void unRegisterGlobal( const URI* uri );
		bool exists( const URI* uri, short compare_method=2 );

		long list( const URI* parent, bool recursive, std::vector<ISerializable*>& all_uris );

		static URICollector& getInstance(); // meyer singleton

	protected:
		URICollector();

		TreeT<NodeUriStr> URIs;

		friend class wosh::URI;

	public:
		~URICollector();

}; // class def


}; // namespace wosh

#endif //__WOSH_Core_Object_H__
